#include "./sensor.h"
#include "../../device/gpio.h"
#include "../../service/heat/config_info.h"

namespace driver {

using namespace device::gpio;
using namespace service;

using PL = PB<3>;
using CP = PB<4>;
using Q7 = PB<5>;

using LEAK = PC<3>;
using BUCKET_HIGH = PC<4>;
using BUCKET_LOW = PC<5>;
using OUTLET_HIGH = PC<6>;
using OUTLET_LOW = PC<7>;

using FLOW = PB<1>;

static volatile uint16_t flowCount = 0;

Sensor::Sensor() {
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN |
        RCC_APB2ENR_IOPCEN |
        RCC_APB2ENR_AFIOEN;

    config_pp_out<PL, CP>();
    config_float_input<Q7, LEAK, 
        BUCKET_HIGH, BUCKET_LOW, 
        OUTLET_HIGH, OUTLET_LOW,
        FLOW>();
    
    AFIO->EXTICR[0] = AFIO->EXTICR[0] & (~(0x0F << 4)) | (0x01 << 4);
    EXTI->IMR |= 0x01 << 1;
    EXTI->FTSR |= 0x01 << 1;
    NVIC_EnableIRQ(EXTI1_IRQn);
}

uint16_t Sensor::flow_count() {
    return flowCount;
}

uint16_t Sensor::flow() {
    return flowCount * 1000 / configInfo->flow_count_1000ml;
}

void Sensor::flow_reset() {
    flowCount = 0;
}

bool Sensor::is_leak() {
    return LEAK::read();
}

bool Sensor::is_bucket_high() {
    
    return BUCKET_HIGH::read();
}

bool Sensor::is_bucket_low() {
    return BUCKET_LOW::read();
}

bool Sensor::is_outlet_high() {
    return OUTLET_HIGH::read();
}

bool Sensor::is_outlet_low() {
    return OUTLET_LOW::read();
}

uint8_t Sensor::read() {
    AUTO_LOCK(m_mutex);

    uint8_t val = 0;
    PL::clr();
    PL::set();

    for (uint8_t i = 0; i < 8; i ++) {
        val <<= 1;
        if (Q7::read()) {
            val ++;
        }
        CP::set();
        CP::clr();
    }
    return val;
}

}

using namespace driver;

extern "C"
void EXTI1_IRQHandler() {
    if (0x00 == (EXTI->PR & (0x01 << 1))) {
        return;
    }
    EXTI->PR = 0x01 << 1;
    flowCount ++;
}

